<?php

namespace Dongasai\WkProtoPhp;

/**
 * 二进制编码器
 */
class Encoder
{
    private string $buffer = '';

    public function __construct()
    {
        $this->buffer = '';
    }

    /**
     * 写入uint8
     */
    public function writeUint8(int $value): self
    {
        $this->buffer .= chr($value & 0xFF);
        return $this;
    }

    /**
     * 写入int16
     */
    public function writeInt16(int $value): self
    {
        $this->buffer .= chr(($value >> 8) & 0xFF);
        $this->buffer .= chr($value & 0xFF);
        return $this;
    }

    /**
     * 写入uint16
     */
    public function writeUint16(int $value): self
    {
        return $this->writeInt16($value);
    }

    /**
     * 写入int32
     */
    public function writeInt32(int $value): self
    {
        $this->buffer .= chr(($value >> 24) & 0xFF);
        $this->buffer .= chr(($value >> 16) & 0xFF);
        $this->buffer .= chr(($value >> 8) & 0xFF);
        $this->buffer .= chr($value & 0xFF);
        return $this;
    }

    /**
     * 写入uint32
     */
    public function writeUint32(int $value): self
    {
        return $this->writeInt32($value);
    }

    /**
     * 写入int64
     */
    public function writeInt64(int $value): self
    {
        $this->buffer .= chr(($value >> 56) & 0xFF);
        $this->buffer .= chr(($value >> 48) & 0xFF);
        $this->buffer .= chr(($value >> 40) & 0xFF);
        $this->buffer .= chr(($value >> 32) & 0xFF);
        $this->buffer .= chr(($value >> 24) & 0xFF);
        $this->buffer .= chr(($value >> 16) & 0xFF);
        $this->buffer .= chr(($value >> 8) & 0xFF);
        $this->buffer .= chr($value & 0xFF);
        return $this;
    }

    /**
     * 写入uint64
     */
    public function writeUint64(int $value): self
    {
        return $this->writeInt64($value);
    }

    /**
     * 写入字符串（先写入长度，再写入内容）
     */
    public function writeString(string $value): self
    {
        return $this->writeBinary($value);
    }

    /**
     * 写入二进制数据（先写入长度，再写入内容）
     */
    public function writeBinary(string $value): self
    {
        $length = strlen($value);
        $this->writeInt16($length);
        $this->buffer .= $value;
        return $this;
    }

    /**
     * 写入字节数组
     */
    public function writeBytes(string $value): self
    {
        $this->buffer .= $value;
        return $this;
    }

    /**
     * 写入可变长度整数
     */
    public function writeVariable(int $size): self
    {
        while ($size > 0) {
            $digit = $size % 0x80;
            $size = intdiv($size, 0x80);
            
            if ($size > 0) {
                $digit |= 0x80;
            }
            
            $this->buffer .= chr($digit);
        }
        
        return $this;
    }

    /**
     * 获取编码后的数据
     */
    public function getBuffer(): string
    {
        return $this->buffer;
    }

    /**
     * 清空缓冲区
     */
    public function clear(): self
    {
        $this->buffer = '';
        return $this;
    }

    /**
     * 获取当前缓冲区长度
     */
    public function length(): int
    {
        return strlen($this->buffer);
    }
}